package edu.byu.intex2.data.dao;

import edu.byu.intex2.data.dao.*;
import java.sql.*;
import java.util.*;

/*******************************************************************************
 *
 *        @author Adam
 *          Date: Mar 3, 2009
 *   Description:
 * Last Revision: Mar 3, 2009
 *
 ******************************************************************************/

public class TechnicianDAO {

    /////////////////////////////////////////////
    ///   Singleton code
    private static TechnicianDAO instance = null;

    /** Creates a new instance of TechnicianDAO */
    private TechnicianDAO() {
    }//constructor

    /** Retrieves the single instance of this class */
    public static synchronized TechnicianDAO getInstance() {
        if (instance == null) {
            instance = new TechnicianDAO();
        }
        return instance;
    }//getInstance

    ////////////////////////////////////////////
    ///   CREATE methods
    /** Creates a new Technician in the database */
    public Technician create(String id) throws DataException {
        Technician technician = new Technician(id);
        technician.setObjectAlreadyInDB(false);
        Cache.getInstance().put(technician.getId(), technician);
        return technician;
    }//create

    ////////////////////////////////////////////
    ///   READ methods
    /** Reads an existing Technician from the database */
    public Technician read(String id) throws DataException {
        if (Cache.getInstance().containsKey(id)) {
            return (Technician) Cache.getInstance().get(id);
        }//if
        Connection conn = ConnectionPool.getInstance().get();
        try {
            return read(id, conn);
        } catch (Exception e) {
            throw new DataException("An error occurred while reading the business object information.", e);
        } finally {
            ConnectionPool.getInstance().release(conn);
        }//finally
    }

    /** Reads an existing Technician from the database */
    public List<Technician> readBy(String colName, String item) throws DataException {
        Connection conn = ConnectionPool.getInstance().get();
        try {
            PreparedStatement stmt = conn.prepareStatement("SELECT * FROM technician where " + colName + "=? ORDER BY ID");
            stmt.setString(1, item);
            return search(stmt, conn);
        } catch (Exception e) {
            try {
                conn.rollback();
            } catch (SQLException e2) {
                throw new DataException("Could not roll back the database transaction!", e2);
            }
            throw new DataException("An error occurred while reading the business object information.", e);
        } finally {
            ConnectionPool.getInstance().release(conn);
        }
    }

    /** Internal method to read an existing Technician from the database */
    synchronized Technician read(String id, Connection conn) throws Exception {
        if (Cache.getInstance().containsKey(id)) {
            return (Technician) Cache.getInstance().get(id);
        }

        PreparedStatement stmt = conn.prepareStatement("SELECT * FROM technician where ID=?");
        try {
            stmt.setString(1, id);
            ResultSet rs = stmt.executeQuery();
            if (rs.next()) {
                return readRecord(rs, conn);
            }//if
            throw new DataException("Technician with id '" + id + "' not found.");
        } finally {
            stmt.close();
        }//finally
    }//read

    void read(Technician t, Connection conn) throws DataException {
        try {
            PreparedStatement stmt = conn.prepareStatement("SELECT * FROM technician where ID=?");
            try {
                stmt.setString(1, t.getId());
                ResultSet rs = stmt.executeQuery();
                if (rs.next()) {
                    t.setServiceFacilityID("ID");
                    t.setDirty(false);
                } else {
                    throw new DataException("Technician with id '" + t.getId() + "' not found.");
                }
            } finally {
                stmt.close();
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    /** Internal method to create a Technician object from a record */
    synchronized Technician readRecord(ResultSet rs, Connection conn) throws Exception {
        if (Cache.getInstance().containsKey(rs.getString("ID"))) {
            return (Technician) Cache.getInstance().get(rs.getString("ID"));
        }
        Technician technician = new Technician(rs.getString("ID"));
        EmployeeDAO.getInstance().read(technician, conn);
        technician.setObjectAlreadyInDB(true);
        Cache.getInstance().put(technician.getId(), technician);//this puts the object to cache
        technician.setServiceFacilityID("ID");
        technician.setDirty(false);

        return technician;
    }//readRecord

    /////////////////////////////////////////////
    ///   UPDATE methods
    /** Saves an existing Technician in the database */
    public void save(Technician technician) throws DataException {
        Connection conn = ConnectionPool.getInstance().get();
        try {
            save(technician, conn);
            conn.commit();
            technician.setDirty(false);
        } catch (Exception e) {
            try {
                conn.rollback();
            } catch (SQLException e2) {
                throw new DataException("Could not roll back the database transaction!", e2);
            }
            throw new DataException("An error occurred while saving the business object information.", e);
        } finally {
            ConnectionPool.getInstance().release(conn);
        }
    }//update

    /** Internal method to update a Technician in the database */
    void save(Technician technician, Connection conn) throws Exception {
        Cache.getInstance().put(technician.getId(), technician);
        if (technician.isObjectAlreadyInDB() && technician.isDirty()) {
            update(technician, conn);
        } else if (technician.isDirty()) {
            insert(technician, conn);
        }//if
    }//save

    /** Saves an existing Technician to the database */
    void update(Technician technician, Connection conn) throws Exception {
        PreparedStatement stmt = conn.prepareStatement("UPDATE technician SET ID=? WHERE ID=?");
        try {
            EmployeeDAO.getInstance().update(technician, conn);//updates the personDAO becasue of
            stmt.setString(1, technician.getServiceFacilityID());
            stmt.setString(2, technician.getId());
            stmt.execute();

        } finally {
            stmt.close();
        }
    }

    /** Inserts a new Technician into the database */
    void insert(Technician technician, Connection conn) throws Exception {
        PreparedStatement stmt = conn.prepareStatement("INSERT INTO technician (ID, ID) VALUES (?)");
        try {
            EmployeeDAO.getInstance().insert(technician, conn);//either updates the PersonDAO or Inserts it
            stmt.setString(1, technician.getId());
            stmt.setString(2, technician.getServiceFacilityID());
            stmt.execute();
            technician.setObjectAlreadyInDB(true);

        } finally {
            stmt.close();
        }
    }

    /////////////////////////////////////////////////
    ///   DELETE methods
    /** We do not support deleting of business objects in this application */
    public void delete(Technician e) throws DataException {
        throw new RuntimeException("The delete function is not supported in this application.");
    }

    ////////////////////////////////////////////////
    ///   SEARCH methods
    /** Retrieves all Technicians from the database */
    public List<Technician> getAll() throws DataException {
        Connection conn = ConnectionPool.getInstance().get();
        try {
            PreparedStatement stmt = conn.prepareStatement("SELECT * FROM technician ORDER BY ID");
            return search(stmt, conn);
        } catch (Exception e) {
            try {
                conn.rollback();
            } catch (SQLException e2) {
                throw new DataException("Could not roll back the database transaction!", e2);
            }
            throw new DataException("An error occurred while reading the business object information.", e);
        } finally {
            ConnectionPool.getInstance().release(conn);
        }
    }

    /** Internal method to search by certain fields */
    private List<Technician> search(PreparedStatement stmt, Connection conn) throws Exception {
        List<Technician> technicians = new LinkedList<Technician>();
        try {
            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {
                technicians.add(readRecord(rs, conn));
            }
        } finally {
            stmt.close();
        }
        return technicians;
    }

}
